by David Lowndes
In This Chapter
In this chapter, you will learn about the CWinApp object. In doing so, I hope to encourage you to examine the MFC source code and discover what happens beneath the surface of your MFC application.
The CWinApp class is the starting point of your MFC application. It controls the initialization and startup operations, runs the main message loop, and handles shutdown. CWinApp can handle command messages in the same way as your view and document classes, and it contains several important public member variables that set the help file, the root registry key, and other system-wide settings for your application.
A CWinApp object never appears directly in your application; instead, it is the base class of your application object. This is a global object named theApp, created by AppWizard in your main application source file. If you use AppWizard to create a project named MyProject, your application class is named CMyProjectApp and the theApp object is declared in MyProject.cpp.
Because it is a global variable, this object is instantiated along with any other global C++ objects as part of the runtime startup code. You can access it from anywhere in your source code using the AfxGetApp function like this:
CMyApp * pApp = static_cast<CMyApp*>( AfxGetApp() );
Because the object is a global variable, you might wonder why MFC exposes it this way rather than providing an extern definition in a header file. In the context of your executable, you could just as well access the object directly, but in the context of an MFC DLL, it is significant. Listing 6.1, a code snippet of an exported function in an MFC DLL, illustrates the point.
Listing 6.1 AfxGetApp and Application Module State
BOOL PASCAL ExportedFunction1( )
{
CWinApp * pApp = AfxGetApp();
AFX_MANAGE_STATE(AfxGetStaticModuleState());
pApp = AfxGetApp();
The returned pApp object pointer from the first call to AfxGetApp is the calling applications CWinApp object. The result of the second call to AfxGetApp is the DLLs CWinApp object. This apparent switch is accomplished by the AFX_MANAGE_STATE macro. It constructs an object that chains a module state to the calling applications module data, so that in this example, the DLL module state (returned by the call to AfxGetStaticModuleState) is linked to the application. Theres no need to remember to reset these state variables; its done automatically by the objects destructor when the function exits.
Its common to use AFX_MANAGE_STATE in any exported MFC DLL functions where you want the program to use a resource from the DLL.
If you are writing an EXE application, you can add the following extern definition to your application objects header file and access the global theApp object directly in any source file that includes the header file:
extern CMyProjectApp theApp;
As mentioned previously, the CWinApp-derived object is a global variable, and therefore exists for the lifetime of your program.
The class member variables are initialized by the classs constructor code. Because the object is global, the constructor is called by the compilers runtime startup code, and therefore all the default values are set before the main part of your program code executes.
After global variables and other aspects of the C runtime support are initialized, your program code executes and is essentially as straightforward as the pseudocode in Listing 6.2.
Listing 6.2 Program Execution Sequence
if ( InitInstance() )
{
Run;
}
else
{
Destroy the main window if there is one;
}
ExitInstance;
In practice, if you examine the MFC source code in WinMain.cpp, youll find that its a little more involved, but this simple representation expresses the general idea.
Its rare that youll need to know about or override the default implementations of Run or ExitInstance, but its almost mandatory for you to modify the boilerplate code for your applications InitInstance.
InitInstance
InitInstance performs all the application-specific initialization. Ill cover this in depth later in the chapter (see InitInstanceApplication-Specific Initialization).
Run
Run is the heart of your application and is where your application spends the vast majority of its processing life. This function is a loop that retrieves and processes messages from your applications message queue. If there are no messages in the queue, it calls the OnIdle function. If there is a message, and its not WM_QUIT, it is dispatched into the MFC message processing code. If the message is WM_QUIT, the loop ends and the function returns. You can think of the Run function as something like the pseudocode in Listing 6.3.
Listing 6.3 Run() Pseudocode
for (;;)
{
MSG msg;
while ( !PeekMessage( &msg, ...) )
{
OnIdle();
}
if ( msg.message == WM_QUIT )
{
return ExitInstance();
}
else
{
DispatchMessage( &msg );
}
}
Ill discuss the path that dispatched messages take later on in this chapter under the Message Routing topic.
ExitInstance
Youre only likely to need to override the ExitInstance member function if you need to free some special allocated resource that your application used. The return value from ExitInstance is the exit code value that your application returns on termination. The normal convention is to return zero if the application shuts down normally, and any other value to indicate an error.
Tip:If you override ExitInstance, be sure to call the base class function because it saves your application Registry settings and performs necessary cleanup of resources used by MFC.
OnIdle
Override the OnIdle function if you need to perform background processing in your application. OnIdle is covered in more depth under Idle Processing later in the chapter.
The CWinApp data members are documented in the Visual C++ help, but the help doesnt give any examples of typical values that these variables take. Ive included a few examples of those public member variables that you might find useful in your own programs.
Note:Some of these members are actually declared in CWinThread (which is the base class of CWinApp), but for now, you can regard them as being part of CWinApp.